<?php


require_once './lib/Unirest/lib/Unirest.php';

if( !function_exists('apache_request_headers') ) {
///
	function apache_request_headers() {
		$arh = array();
		$rx_http = '/\AHTTP_/';
		foreach($_SERVER as $key => $val) {
			if( preg_match($rx_http, $key) ) {
				$arh_key = preg_replace($rx_http, '', $key);
				$rx_matches = array();
				// do some nasty string manipulations to restore the original letter case
				// this should work in most cases
				$rx_matches = explode('_', $arh_key);
				if( count($rx_matches) > 0 and strlen($arh_key) > 2 ) {
					foreach($rx_matches as $ak_key => $ak_val) $rx_matches[$ak_key] = ucfirst($ak_val);
					$arh_key = implode('-', $rx_matches);
				}
				$arh[$arh_key] = $val;
			}
		}
		return( $arh );
	}
///
}


date_default_timezone_set('GMT');
define('CACHE_ENABLED', true);
define('CACHE_DURATION_SECONDS', 15 * 60);
define('CACHE_FOLDER', 'cache/');
define('COOKIE_TOKEN_DURATION_SECONDS', 8 * 3600);
define('COOKIE_TOKEN_NAME', 'dnb_direct_2_auth_token');
    
// Get config
$config = json_decode(file_get_contents('settings.json'), 1);

// Get REST resource, headers, body, and cookie path
$resource  = isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : '/';
$resource  = substr($resource, 1);
$qs = $_SERVER['QUERY_STRING'];
if (strlen($qs))
	$resource .= "?" . $qs;
$json_body = @file_get_contents('php://input');
$req_headers = apache_request_headers();
$cookie_path = '';
$proxy_path = $_SERVER['REQUEST_URI'];
$proxy_path = substr($proxy_path, 0, strlen($proxy_path) - strlen($resource) - 1);
$parts = explode('/', $proxy_path);
array_pop($parts);
array_pop($parts);
$cookie_path = join('/', $parts);
$cookie_path .= '/';

$token = isset($req_headers['Authorization']) ? $req_headers['Authorization'] : '';
$debug = array();
$cookie_token = isset($_COOKIE[COOKIE_TOKEN_NAME]) ? $_COOKIE[COOKIE_TOKEN_NAME] : '';
if ($cookie_token)
{
	$token = $cookie_token;
	$debug[] = 'token-from-cookie';
}

if (!$token)
{
	$token_response = get_token($config['username'], $config['password']);
	$token = $token_response->headers['Authorization'];
	setcookie(COOKIE_TOKEN_NAME, $token, time() + COOKIE_TOKEN_DURATION_SECONDS, $cookie_path);
	$debug[] = 'auth-set-cookie';
}
else
{
	setcookie(COOKIE_TOKEN_NAME, $token, time() + COOKIE_TOKEN_DURATION_SECONDS, $cookie_path);
	$debug[] = 'auth-set-cookie';
}

// special case...
if ($resource=='dev/null' || $resource=='_cookieAuth')
{
	$resp = array('json'=>'{}');
	$debug[] = 'null';
}
else
{
	// Call D&B Direct
	$url = $config['endpoint'] . $resource;
	$resp = json_call($url);
	$debug[] = 'cache-' . ($resp['cache_hit']?'hit':'miss');
}

// Apply filter if needed
if(file_exists('local_filter.php'))
{
	$debug[] = 'local-filter';
	include 'local_filter.php';
}

// Send back response
header("Content-Type: application/json");
header("X-Powered-By: D&B Direct");
header('Cache-Control: max-age=31556926');
header('X-Direct-Trace: ' . join(", ", $debug));

print $resp['json'];
// ---------- FIN ----------

function get_token($username, $password)
{
	global $config;

	$url = $config['endpoint'] . 'rest/Authentication';
	$headers = array('x-dnb-user' => $username, 'x-dnb-pwd' => $password);
	$response = Unirest::post($url, $headers);
	return $response;
}

function invoke_rest($url, $json_body = null)
{
	global $token;
	global $headers;

	$headers = array('Authorization' => $token);
	$response = Unirest::get($url, $headers);
	$resp = array('json'=>$response->raw_body, 'code'=>$response->code);
	return $resp;
}


function json_call($resource, $json_body = null)
{
	$fx = create_function('$resource, $json_body', 'return invoke_rest($resource, $json_body);');
	$resp = CACHE_ENABLED ? DnBSimpleCache::cache($resource, $json_body, $fx) : $fx($resource, $json_body, $fx);
	return $resp;
}



class DnBSimpleCache
{
	private static function cache_file_expired($file)
	{
		$age_in_secs = time() - filemtime($file);
		return $age_in_secs > CACHE_DURATION_SECONDS;
	}

	public static function cache()
	{
		$params = func_get_args();
		$fx = array_pop($params);
    
		$cache_hit = false;
		$cache_key = md5(json_encode($params));
		$cache_file = CACHE_FOLDER . $cache_key . '.json';
		header("X-Direct-Cache-Key: $cache_key");
    
		if (CACHE_ENABLED && file_exists($cache_file))
		{
			$cache_hit = !DnBSimpleCache::cache_file_expired($cache_file);
		}
            
		if ($cache_hit)
		{
			$rv = array('code'=>200, 'json'=>file_get_contents($cache_file), 'cache_hit'=>1);
		}
		else
		{
			$rv = call_user_func_array($fx, $params);
			$rv['cache_hit'] = 0;
			if (CACHE_ENABLED && $rv['code']==200)
			{
				try {
					$r = file_put_contents($cache_file, $rv['json']);
				} catch (Exception $e) {}
			}
		}
    
		if (CACHE_ENABLED)
			DnBSimpleCache::cleanup();
		return $rv;
	}
        
	public static function cleanup()
	{
		DnBSimpleCache::flush();
	}
        
	public static function flush($everything = false)
	{
		foreach (glob(CACHE_FOLDER . "*.json") as $filename)
			if ($everything || DnBSimpleCache::cache_file_expired($filename))
				unlink($filename);
	}
}
